#include "simMetaInfo.h"
#include "offlineRelay.h"

#define SIGNAL_FREQ 50.0 // 电气量的频率

RawData* readDataFromFile(char* fileName);
int maxValOfIntArray(const int* array, int size);
void offlineCalculate(LineRelayMetaInfo* meta[]);

double*** portM, ***portN; //[length][portCount][maxPortSize]
double** tripSignal[2];

int main() {
    
    // TODO M侧 & N侧的保护装置个数
    int deviceCountM = 1;
    int deviceCountN = 1;
    // TODO ========

    char* deviceNameM[deviceCountM]; // 装置名称
    char* deviceNameN[deviceCountN];

    Device linesM[deviceCountM]; // 装置结构体
    Device linesN[deviceCountN];
    
    char* fileNameM[deviceCountM]; // 装置信号文件名csv
    char* fileNameN[deviceCountN];
    
    int portCountM[deviceCountM]; // 装置端口数
    int portCountN[deviceCountN];
    
    int* portSizeM[deviceCountM]; // 端口信号维数
    int* portSizeN[deviceCountN];
    
    int tripSizeM[deviceCountM]; // 输出信号维数
    int tripSizeN[deviceCountN];
    
    // TODO M侧 & N侧的保护装置基本信息初始化 
    char* fileName = "F:\\offlineCalculate\\1.csv";
    deviceNameM[0] = "line5M"; // 与配置文件名一致，xxx -> xxx.conf
    fileNameM[0] = fileName; // csv格式，绝对路径，建议不包含中文
    portCountM[0] = 2;
    portSizeM[0] = (int*)malloc(sizeof(int) * portCountM[0]);
    portSizeM[0][0] = 10; // port1维数
    portSizeM[0][1] = 10; // port2维数
    tripSizeM[0] = 3; // 输出信号维数

    deviceNameN[0] = "line5N"; // 与配置文件名一致，xxx -> xxx.conf
    fileNameN[0] = fileName; // csv格式，绝对路径，建议不包含中文
    portCountN[0] = 2;
    portSizeN[0] = (int*)malloc(sizeof(int) * portCountN[0]);
    portSizeN[0][0] = 10; // port1维数N
    portSizeN[0][1] = 10; // port2维数
    tripSizeN[0] = 3; // 输出信号维数
    
    // TODO =======
    
    LineRelayMetaInfo* metasM[deviceCountM];
    LineRelayMetaInfo* metasN[deviceCountM];
    for (int i = 0; i < deviceCountM; i++) {
        metasM[i] = NewLineRelayMetaInfo(
                deviceNameM[i],
                &linesM[i],
                &linesN[i],
                fileNameM[i],
                portCountM[i],
                portSizeM[i],
                tripSizeM[i]);
    }

    for (int i = 0; i < deviceCountN; i++) {
        metasN[i] = NewLineRelayMetaInfo(
                deviceNameN[i],
                &linesN[i],
                &linesM[i],
                fileNameN[i],
                portCountN[i],
                portSizeN[i],
                tripSizeN[i]);
    }
    LineRelayMetaInfo* devices[deviceCountM][2];

    for (int i = 0; i < deviceCountM; i++) {
        devices[i][0] = metasM[i];
        devices[i][1] = metasN[i];
        offlineCalculate(devices[i]);
    }

    return 0;
}

RawData* readDataFromFile(char* fileName) {
    FILE* file = fopen(fileName, "r");
    int i, j;

    if (fileName == NULL) {
        printf("FileName is NULL!");
        return NULL;
    }
    // new struct
    RawData* rawData = NewCsvData(GetTotalRowCount(file), GetTotalColCount(file, ','));
    loadDataFromFile(rawData, file);
    fclose(file);
    return rawData;
}

void offlineCalculate(LineRelayMetaInfo* meta[]) {
    if (meta == NULL) {
        printf("[ERROR]Line relay meta info is NULL!\n");
        return;
    }

    RawData* csvData[2];
    csvData[0] = readDataFromFile(meta[0]->dataFileName);
    csvData[1] = readDataFromFile(meta[1]->dataFileName);
    if (csvData[0] == NULL || csvData[1] == NULL) {
        printf("[ERROR]Read Csv file failed!\n");
        return;
    }

    SimMetaInfo* metaInfo[2];
    metaInfo[0] = loadMetaInfoFromRawData(csvData[0], SIGNAL_FREQ);
    metaInfo[1] = loadMetaInfoFromRawData(csvData[1], SIGNAL_FREQ);
    if (metaInfo[0] == NULL || metaInfo[1] == NULL) {
        printf("[ERROR]Init simulation meta info failed.\n");
        return;
    }
    int length[2];
    length[0] = metaInfo[0]->signalLength;
    length[1] = metaInfo[1]->signalLength;
    // 2. 开辟保护装置输入，输出信号的数组空间
    int portCount[2];
    portCount[0] = meta[0]->portCount;
    portCount[1] = meta[1]->portCount;
    int* portSize[2];
    portSize[0] = meta[0]->portSize;
    portSize[1] = meta[1]->portSize;

    int maxPortSize[2];
    maxPortSize[0] = maxValOfIntArray(portSize[0], portCount[0]);
    maxPortSize[1] = maxValOfIntArray(portSize[1], portCount[1]);
    int portOffsetM[portCount[0]];
    int portOffsetN[portCount[1]];
    for (int i = 0; i < portCount[0]; i++) {
        if (i == 0) {
            portOffsetM[i] = 1;
        } else {
            portOffsetM[i] = portOffsetM[i - 1] + portSize[0][i - 1];
        }
    }

    for (int i = 0; i < portCount[1]; i++) {
        if (i == 0) {
            portOffsetN[i] = 1;
        } else {
            portOffsetN[i] = portOffsetN[i - 1] + portSize[1][i - 1];
        }
    }

    double time[length[0]];
    portM = (double***)malloc(sizeof(double**) * length[0]);
    for (int i = 0 ; i < length[0]; i++) {
        portM[i] = (double**)malloc(sizeof(double*) * portCount[0]);
        for (int j = 0; j < portCount[0]; j++) {
            portM[i][j] = (double*)malloc(sizeof(double) * maxPortSize[0]);
        }
    }

    portN = (double***)malloc(sizeof(double**) * length[1]);
    for (int i = 0 ; i < length[1]; i++) {
        portN[i] = (double**)malloc(sizeof(double*) * portCount[1]);
        for (int j = 0; j < portCount[1]; j++) {
            portN[i][j] = (double*)malloc(sizeof(double) * maxPortSize[1]);
        }
    }

    int tripSignalSize = 3; // 输出信号维数

    for (int i = 0 ; i < 2; i++) {
        tripSignal[i] = (double**)malloc(sizeof(double*) * length[i]);
        for (int j = 0; j < length[i]; j++) {
            tripSignal[i][j] = (double*)malloc(sizeof(double) * 3);
        }
    }
    // 3. 将文件数据填入对应的信号数组中，csv文件中排列的格式为：时间，port1的各信号列（严格按照在线时的信号顺序从左到右排列），port2的各信号序列...
    for (int i = 0; i < length[0]; i++) {
        time[i] = csvData[0]->data[i][0];
        portM[i][0][0] = csvData[0]->data[i][7]; // volt
        portM[i][0][1] = csvData[0]->data[i][8]; 
        portM[i][0][2] = csvData[0]->data[i][9]; 
        portM[i][0][3] = csvData[0]->data[i][1]; // curr
        portM[i][0][4] = csvData[0]->data[i][2]; 
        portM[i][0][5] = csvData[0]->data[i][3]; 
        portM[i][0][6] = portM[i][0][7] = portM[i][0][8] = 0.0; // brk
        portM[i][0][9] = portM[i][0][3] + portM[i][0][4] + portM[i][0][5]; // zero

        portM[i][1][0] = csvData[0]->data[i][10]; // volt
        portM[i][1][1] = csvData[0]->data[i][11];
        portM[i][1][2] = csvData[0]->data[i][12];
        portM[i][1][3] = csvData[0]->data[i][4]; // curr
        portM[i][1][4] = csvData[0]->data[i][5];
        portM[i][1][5] = csvData[0]->data[i][6];
        portM[i][1][6] = portM[i][1][7] = portM[i][1][8] = 0.0; // brk
        portM[i][1][9] = portM[i][1][3] + portM[i][1][4] + portM[i][1][5]; // zero
    }
    for (int i = 0; i < length[1]; i++) {
        portN[i][0][0] = csvData[1]->data[i][10]; // volt
        portN[i][0][1] = csvData[1]->data[i][11];
        portN[i][0][2] = csvData[1]->data[i][12];
        portN[i][0][3] = csvData[1]->data[i][4]; // curr
        portN[i][0][4] = csvData[1]->data[i][5];
        portN[i][0][5] = csvData[1]->data[i][6];
        portN[i][0][6] = portN[i][0][7] = portN[i][0][8] = 0.0; // brk
        portN[i][0][9] = portN[i][0][3] + portN[i][0][4] + portN[i][0][5]; // zero

        portN[i][1][0] = csvData[1]->data[i][7]; // volt
        portN[i][1][1] = csvData[1]->data[i][8];
        portN[i][1][2] = csvData[1]->data[i][9];
        portN[i][1][3] = csvData[1]->data[i][1]; // curr
        portN[i][1][4] = csvData[1]->data[i][2];
        portN[i][1][5] = csvData[1]->data[i][3];
        portN[i][1][6] = portN[i][1][7] = portN[i][1][8] = 0.0; // brk
        portN[i][1][9] = portN[i][1][3] + portN[i][1][4] + portN[i][1][5]; // zero
    }

    char* deviceName[2];
    deviceName[0] = meta[0]->deviceName;
    deviceName[1] = meta[1]->deviceName;
    Device* local = meta[0]->localDevice;
    Device* remote = meta[0]->remoteDevice;

    for (int i = 0; i < length[0]; i++) {
        // 4. 调用保护函数，统一定义在 offlineRelay.c 和 offlineRelay.h中
        meta[0]->relayFunc(deviceName[0], local, remote, &time[i], portM[i][0], portM[i][1], tripSignal[0][i]);
        meta[1]->relayFunc(deviceName[1], remote, local, &time[i], portN[i][0], portN[i][1], tripSignal[1][i]);
    }
}

int maxValOfIntArray(const int* array, int size) {
    if (array == NULL) {
        printf("array is NULL!\n");
        return 0;
    }

    int max = 0;
    for (int i = 0; i < size; i++) {
        max = max > array[i] ? max : array[i];
    }

    return max;
}
